非UI线程可以更新UI?
前言
我们都知道,不能在非UI线程中更新UI,但是今天再次接触Handle,实验的时候,发现了一个很奇妙的问题,于是记录一下。
1 2 3 4 5 6 7 8 9 10 11 12
| protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.tv_result); new Thread(){ @Override public void run() { mTextView.setText("2333"); } }.start(); }
|
你猜猜执行会怎么着?竟然不会Crash,但是以下代码就会Crash。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.tv_result); new Thread(){ @Override public void run() { try { Thread.sleep(2000); mTextView.setText("2333"); } catch (InterruptedException e) { e.printStackTrace(); } // mTextView.setText("2333"); } }.start(); }
|
难道说和线程休眠有关?也不会呀,休不休眠它还是在非UI线程之中呀。那问题出在哪里了呢?
原因竟然是
在做UI更新的时候,会执行当前线程是否是UI线程的检查,即通过检查ViewRoot的线程和当前线程是否一致来判断是否是UI线程,一般来说,WiewRoot所在的线程就是UI线程。在OnCreate()的时候,ViewRoot还没有被创建,所以没法执行检查是否是UI线程。那在什么时候ViewRoot会被创建呢?答案是在执行onResume完成后,ViewRoot就能创建好了,这个时候就会执行UI线程检查了。
验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56
| protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTextView = (TextView) findViewById(R.id.tv_result); mButtonTest = (Button) findViewById(R.id.btn_test); mThread = new Thread() { @Override public void run() { mTextView.setText("onCreate"); } }; mButtonTest.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { mThread.start(); } }); Log.i("2333", "onCreate"); } @Override protected void onStart() { super.onStart(); new Thread(){ @Override public void run() { mTextView.setText("onStart"); } }.start(); Log.i("2333", "onStart"); } @Override protected void onResume() { super.onResume(); new Thread(){ @Override public void run() { mTextView.setText("onResume"); } }.start(); Log.i("2333", "onResume"); } @Override protected void onStop() { super.onStop(); new Thread(){ @Override public void run() { mTextView.setText("onStop"); } }.start(); Log.i("2333", "onStop"); }
|
根据打印的Log我们就能知道,是在onResume执行完之后才会进行UI线程的检查,参考的博客实际上是说执行到onResume就会检查了,看来还是自己动手实验一下比较有说服力。
参考:
http://bbs.csdn.net/topics/390871177?page=1
http://michaelye1988.iteye.com/blog/1923093
由源码分析可见以下:
http://www.cnblogs.com/yydcdut/p/3864072.html
保持好奇心!